﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;

namespace dis.sys.hw1.Contract
{
    [AttributeUsage(AttributeTargets.Class)]
    public class Logging : Attribute, IServiceBehavior
    {
        public string logfilename;
        public Logging(string logfilename)
        {
            this.logfilename = logfilename;
        }

        public void ApplyDispatchBehavior(ServiceDescription desc, ServiceHostBase host)
        {
            foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers)
            {
                foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
                {
                    foreach (DispatchOperation op in eDispatcher.DispatchRuntime.Operations)
                    {
                        op.ParameterInspectors.Add(new LoggingInspector(logfilename));
                    }
                }
            }
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        internal class LoggingInspector : IParameterInspector
        {
            private string logfilename;
            private DateTime startTime;
            private  string logdata;

            public LoggingInspector(string logfilename)
            {
                this.logfilename = logfilename;
            }


            #region IParameterInspector Members


            public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
            {
                var lines = new[] { DateTime.UtcNow - startTime + " - " + logdata };
                System.IO.File.WriteAllLines(logfilename, lines);
            }

            public object BeforeCall(string operationName, object[] inputs)
            {
                startTime = DateTime.UtcNow;
                logdata = GetCallInputParameters(operationName, inputs);
                return null;
            }

            private static string GetCallOutputParameters(String operationName, Object returnValue)
            {
                return String.Format
                    ("Output for operation '{0}': '{1}'",
                     operationName,
                     (returnValue == null ? "Null" : returnValue.ToString()));
            }

            private static string GetCallInputParameters(string operationName, Object[] objects)
            {
                String[] inputs = new string[objects.Length];
                for (int i = 0; i < objects.Length; i++)
                {
                    inputs[i] = (objects[i] == null ? "Null" : objects[i].ToString());
                }
                return String.Format
                    ("Input for operation '{0}': '{1}'",
                    operationName,
                    String.Join(", ", inputs));
            }

            #endregion
        }
    }
}
